home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FM Towns: Free Software Collection 8
/
FM Towns Free Software Collection 8.iso
/
t_os
/
wink24h
/
src
/
bplus.c
next >
Wrap
Text File
|
1994-06-01
|
40KB
|
1,629 lines
/**************************************************************************
FMR version Makeing by ken 89.9.5
***************************************************************************/
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <fmcfrb.h>
#include "defs.h"
#define TRUE 1
#define FALSE 0
#define ERR (-1)
#define UNSIG unsigned short
#define unlink remove
#define Async_Send(c) send_aux(c)
#define Bufferd_Recive recv_aux
#define Bufferd_Send(c) send_aux(c)
void Bufferd_Flush()
{
}
#define WRITE_OP "wb"
#define READ_OP "rb"
#define UPDATE_OP "r+b"
extern unsigned char *cvram;
extern void Send_Failure();
extern int kbhit();
extern int getch();
extern void wrtstr();
extern void Dmy_form();
extern void Dsp_vram();
extern int recv_aux();
extern void send_aux();
#define STMsg 0
#define STFile 1
#define STUpDow 2
#define STType 3
#define STComSent 4
#define STDataSent 5
#define STErrSent 6
#define STPacSent 7
#define STComRate 8
#define STDataRate 9
#define STElapsed 10
#define STComRead 20
#define STDataRead 21
#define STErrRead 22
#define STPacRead 23
#define STUplSize 24
#define STDowSize 25
#define STUplRem 26
#define STDowRem 27
#define STRemTime 28
int ST_Check_Abort()
{
if ( kbhit() != 0 && getch() == '\x1B' )
return 1;
return 0;
}
void ST_Yes_or_No(arg,yn)
char *arg;
char *yn;
{
wrtstr(arg,17,20,0x02);
*yn = getch();
}
void ST_Initialize()
{
int i;
char tmp[160];
static char *menu[]={
"Msg ","File ","UpDow ","Type ","ComSent ",
"DataSent","ErrSent ","PacSent ","ComRate ","DataRate",
"Elapsed ",
" "," ","ComRead ","DataRead","ErrRead ",
"PacRead ","UplSize ","DowSize ","UplRem ","DowRem ",
"RemTime " };
Dmy_form(tmp,50,0x98,0x95,0x99);
wrtstr(tmp,15,7,0x06);
Dmy_form(tmp,50,0x96,0x20,0x96);
for ( i = 0 ; i < 13 ; i++ )
wrtstr(tmp,15,8+i,0x06);
Dmy_form(tmp,50,0x9A,0x95,0x9B);
wrtstr(tmp,15,21,0x06);
wrtstr(" <<< B Plus Protocol(SM) Abort Hit ESC Key >>>",17,8,0x02);
for ( i = 0 ; i < 22 ; i++ )
wrtstr(menu[i],17+(i/11)*24,9+(i%11),0x06);
}
void ST_Terminate()
{
Dsp_vram(cvram);
}
void ST_Display_String(no,str)
int no;
char *str;
{
wrtstr(str,27+(no/18)*24,9+(no%18),0x06);
}
void ST_Display_Value(no,val)
int no;
long val;
{
char tmp[20];
if ( no == STElapsed || no == STRemTime ) {
if ( val >= 3600 )
sprintf(tmp,"%2ld:%02ld:%02ld",val/3600,(val%3600)/60,val%60);
else if ( val >= 60 )
sprintf(tmp," %2ld:%02ld",val/60,val%60);
else
sprintf(tmp," %2ld",val);
} else
sprintf(tmp,"%8ld",val);
ST_Display_String(no,tmp);
}
#define Def_BS 4 /* Buffer size 128 x n */
#define Max_SA 2 /* Maximum number of waiting Packets */
#define Max_Buf_Size (Def_BS*128+8) /* Largest data block we can handle */
#define Def_Buf_Size 511 /* Default data block */
#define Def_WS 1 /* I can send 2 Packets ahead */
#define Def_WR 1 /* I can receive single send-ahead */
#define Def_CM 1 /* I can handle CRC */
#define Def_DQ 1 /* I can handle non-quoted NUL */
/* (including the `Tf' Packet */
#define Def_UR 0 /* I can NOT handle Upload Recovery */
#define Def_FI 1 /* I can handle File Information */
#define max_Errors 10
#define bps110 0
#define bps150 1
#define bps300 2
#define bps600 3
#define bps1200 4
#define bps1800 5
#define bps2400 6
#define bps4800 7
#define bps9600 8
/* Receive States */
#define R_Get_DLE 0
#define R_Get_B 1
#define R_Get_Seq 2
#define R_Get_Data 3
#define R_Get_Check 4
#define R_Send_ACK 5
#define R_Timed_Out 6
#define R_Success 7
/* Send States */
#define S_Get_DLE 1
#define S_Get_Num 2
#define S_Have_ACK 3
#define S_Get_Packet 4
#define S_Skip_Packet 5
#define S_Timed_Out 6
#define S_Send_NAK 7
#define S_Send_ENQ 8
#define S_Send_Data 9
/* Other Constants */
#define dle 16
#define etx 03
#define nak 21
#define enq 05
typedef struct {
int seq; /* Packet's sequence number */
int num; /* Number of bytes in Packet */
char buf[Max_Buf_Size]; /* Actual Packet data */
} buf_type;
static time_t e_timer;
static int BP_Auto_Resume = TRUE;
static int BP_Use_File_Size = FALSE;
static long BP_File_Size=0L;
static int PortBps = bps2400;
static int seq_num;
static UNSIG checksum;
static char His_WS,His_WR,His_BS,His_CM;
static char His_QS[8];
static char His_DR,His_UR,His_FI;
static char Our_WS,Our_WR,Our_BS,Our_CM;
static char Our_QS[8];
static char Our_DR,Our_UR,Our_FI,Def_DR;
static int Port_Update_Rate;
static int B_Plus;
static int Use_CRC;
static int BP_Special_Quoting = 0;
static int Buffer_Size;
static int SA_Max;
static int SA_Error_Count;
static char Quote_Table[256];
static char BP_Special_Quote_Set[]={
0x14, 0x00, 0xd4, 0x00,
0x00, 0x00, 0x00, 0x00 };
static char DQ_Full[]={
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff };
static char DQ_Default[]={
0x14, 0x00, 0xd4, 0x00,
0x00, 0x00, 0x00, 0x00 };
static char DQ_Minimal[]={
0x14, 0x00, 0xd4, 0x00,
0x00, 0x00, 0x00, 0x00 };
static char DQ_Extended[]={
0x14, 0x00, 0xd4, 0x00,
0x00, 0x00, 0x50, 0x00 };
static int R_Size,ch;
static int Timed_Out,Packet_Received,masked;
static buf_type SA_Buf[Max_SA+1];
static int SA_Next_to_ACK;
static int SA_Next_to_Fill;
static int SA_Waiting;
static int Aborting;
static char R_buffer[Max_Buf_Size];
static char filename[256];
static int S_Counter;
static int R_Counter;
static long S_Com_Data;
static long R_Com_Data;
static long S_File_Data;
static long R_File_Data;
static long S_Packet_Count;
static long R_Packet_Count;
static long S_Error_Count;
static long R_Error_Count;
static long S_File_Size;
static long R_File_Size;
static long S_Remaining;
static long R_Remaining;
static long Com_Rate;
static long Data_Rate;
static long Time_Estimate;
static int Resume_Flag;
static UNSIG crc_16;
static char Val_Str[50];
static int e_i, e_j, e_n;
UNSIG crc_table[] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
void ltoa( n, s )
long n;
char *s;
{
char *t;
long i;
char c;
long sign;
long divten;
if ( (sign = n) < 0 )
n = -n;
t = s;
do {
i = (divten = (n / 10)) * 10;
*(t++) = ( n - i ) + '0';
} while( (n = divten) > 0 );
if( sign < 0 )
*(t++) = '-';
*t = '\0';
t--;
while( s < t ) {
c = *t;
*(t--) = *s;
*(s++) = c;
}
}
static void Clear_Quote_Table()
{
memset(Quote_Table,0,256);
}
static void Update_Quote_Table (Quote_Set)
char *Quote_Set;
{
int i, j, k;
char b, c;
c = 0x40;
k = 0x00;
for ( i = 0 ; i < 8 ; i++ ) {
if ( i == 4 ) {
c = 0x60;
k = 0x80;
}
b = Quote_Set[i];
for ( j = 0 ; j < 8 ; j++ ) {
if ( (b & 0x80) != 0)
Quote_Table[k] = c;
b <<= 1;
c++;
k++;
}
}
}
void BP_Quote_This (Value)
int Value;
{
int i, j;
if ( (Value >= 0x00 && Value <= 0x1F) ||
(Value >= 0x80 && Value <= 0x9f) ) {
if ( Value > 0x1f ) {
i = 4;
Value = Value & 0x1f;
} else
i = 0;
i = i + Value / 8;
j = Value % 8;
BP_Special_Quote_Set[i] |= (0x80 >> j);
BP_Special_Quoting = TRUE;
} else if ( Value == (-1) ) {
for( i=0 ; i < sizeof(DQ_Minimal) ; i++ )
BP_Special_Quote_Set[i] = DQ_Minimal[i];
BP_Special_Quoting = FALSE;
}
}
void BP_Term_ENQ()
{
int i;
seq_num = 0;
Buffer_Size = 512; /* Set up defaults */
Our_WS = 0;
Our_WR = 0;
Our_BS = 4;
Our_CM = 0;
Our_DR = 0;
Our_UR = 0;
Our_FI = 0;
B_Plus = FALSE; /* Not B Plus Protocol */
Use_CRC = FALSE; /* Not CRC_16 */
SA_Max = 1; /* Single Packet send */
SA_Error_Count = 0; /* No Upload errors yet */
for( i = 0 ; i < sizeof(DQ_Minimal) ; i++ )
Our_QS[i] = DQ_Minimal[i];
Clear_Quote_Table();
Update_Quote_Table(Our_QS);
Async_Send(dle);
Async_Send('+');
Async_Send('+');
Async_Send(dle);
Async_Send('0');
}
void BP_Term_ESC_I(esc_I_Res)
char esc_I_Res[];
{
int i;
char t[256];
int cks;
cks = 0;
for ( i = 0 ; i < strlen(esc_I_Res) ; i++ ) {
Async_Send(esc_I_Res[i]);
cks += esc_I_Res[i];
}
Async_Send (',');
Async_Send ('+');
cks = cks + ',' + '+';
ltoa( (long)cks, t );
i = 4 - strlen( t );
while( i-- )
Async_Send( '0' );
for ( i = 0 ; i < strlen(t) ; i++ )
Async_Send(t[i]);
Async_Send(0x0d);
}
static int Init_CRC (value)
int value;
{
return( crc_16 = value );
}
static UNSIG Upd_CRC (value)
UNSIG value;
{
value &= 0xFF;
crc_16 = crc_table [((crc_16 >> 8) ^ (value)) & 0xff] ^ (crc_16 << 8);
return( crc_16 );
}
static void do_checksum (c)
int c;
{
c &= 0xFF;
if ( B_Plus && Use_CRC )
checksum = Upd_CRC (c);
else {
checksum <<= 1;
if (checksum > 255)
checksum = (checksum & 0xff) + 1;
checksum += c;
if (checksum > 255)
checksum = (checksum & 0xff) + 1;
}
}
static void send_count()
{
S_Com_Data++;
if ( (S_Counter++) >= Port_Update_Rate ) {
S_Counter = 0;
ST_Display_Value (STComSent, S_Com_Data);
}
}
static void send_byte (ch)
char ch;
{
Async_Send (ch);
send_count();
}
static void buf_send_byte (ch)
char ch;
{
Bufferd_Send(ch);
send_count();
}
static void send_masked_byte (ch)
int ch;
{
ch &= 0xff;
if (Quote_Table [ch] != 0) {
buf_send_byte(dle);
buf_send_byte(Quote_Table[ch]);
} else
buf_send_byte(ch);
}
static void Send_ACK()
{
send_byte(dle);
send_byte(seq_num + '0');
}
static void Send_NAK()
{
send_byte(nak);
}
static void Send_ENQ()
{
send_byte(enq);
}
static int read_byte()
{
int chx;
int Hiber;
time_t start,now;
Timed_Out = FALSE;
if ( (chx = Bufferd_Recive()) != ERR )
goto ENDOF;
time(&start);
if ( !Aborting )
Hiber = 10;
else
Hiber = 5;
while ( (chx = Bufferd_Recive()) == ERR ) {
time(&now);
if ( (now - start) >= Hiber ) {
Timed_Out = TRUE;
return( FALSE );
}
}
ENDOF:
ch = chx;
R_Com_Data++;
if ( (R_Counter++) >= Port_Update_Rate ) {
R_Counter = 0;
ST_Display_Value(STComRead, R_Com_Data);
}
return(TRUE);
}
static int read_masked_byte()
{
masked = FALSE;
if ( read_byte() == FALSE )
return(FALSE);
if ( ch == dle ) {
if (read_byte() == FALSE)
return(FALSE);
if ( ch < 0x60 )
ch &= 0x1f;
else
ch = (ch & 0x1F) | 0x80;
masked = TRUE;
}
return(TRUE);
}
static int Incr_Seq (value)
int value;
{
if ( value == 9 )
return( 0);
else
return(value + 1);
}
static int Read_Packet (Lead_in_Seen, From_Send_Packet)
int Lead_in_Seen;
int From_Send_Packet;
{
int State,
next_seq,
block_num,
errors,
new_cks;
int i;
int NAK_Sent;
if ( Packet_Received ) {
Packet_Received = FALSE;
return( TRUE);
}
NAK_Sent = FALSE;
memset(R_buffer,0,Buffer_Size);
next_seq = (seq_num + 1) % 10;
errors = 0;
i = 0;
if ( Lead_in_Seen )
State = R_Get_Seq;
else
State = R_Get_DLE;
while( TRUE ) {
switch ( State ) {
case R_Get_DLE :
if ( ST_Check_Abort() && !Aborting ) {
ST_Display_String(STMsg,"Aborting download per your request");
Send_Failure ("AAborted by user");
return(FALSE);
}
if ( !read_byte() )
State = R_Timed_Out;
else if ((ch & 0x7F) == dle )
State = R_Get_B;
else if ((ch & 0x7F) == enq )
State = R_Send_ACK;
break;
case R_Get_B :
if ( !read_byte() )
State = R_Timed_Out;
else if ((ch & 0x7F) == 'B')
State = R_Get_Seq;
else if (ch == enq)
State = R_Send_ACK;
else if (ch == ';') {
ST_Display_Value (STComRead, R_Com_Data);
State = R_Get_DLE;
} else
State = R_Get_DLE;
break;
case R_Get_Seq :
if ( Resume_Flag ) {
time(&e_timer);
R_Com_Data = 2;
}
if ( !read_byte() )
State = R_Timed_Out;
else if ( ch == enq)
State = R_Send_ACK;
else {
if (B_Plus && Use_CRC)
checksum = Init_CRC(0xffff);
else
checksum = 0;
block_num = ch - '0';
do_checksum (ch);
i = 0;
State = R_Get_Data;
}
break;
case R_Get_Data :
if ( !read_masked_byte() )
State = R_Timed_Out;
else if ( (ch == etx) && !masked ) {
do_checksum (etx);
State = R_Get_Check;
} else {
if ( i < Max_Buf_Size ) {
R_buffer[i] = ch;
i++;
do_checksum (ch);
}
}
break;
case R_Get_Check :
if ( !read_masked_byte() )
State = R_Timed_Out;
else {
if ( B_Plus && Use_CRC ) {
checksum = Upd_CRC(ch);
if ( !read_masked_byte() )
new_cks = checksum ^ 0xff;
else {
checksum = Upd_CRC(ch);
new_cks = 0;
}
} else
new_cks = ch;
if (new_cks != checksum) {
ST_Display_String(STMsg,"CRC No Match!");
State = R_Timed_Out;
} else if (R_buffer[0] == 'F') /* Watch for Failure Packet */
State = R_Success; /* which is accepted regardless */
else if (block_num == seq_num) /* Watch for duplicate block */
State = R_Send_ACK; /* Simply ACK it */
else if (block_num != next_seq)
State = R_Timed_Out; /* Bad seq num */
else
State = R_Success;
}
break;
case R_Timed_Out :
errors++;
if ( (errors > max_Errors) || (From_Send_Packet) )
return( FALSE );
if ( !NAK_Sent || !B_Plus ) {
R_Error_Count++;
ST_Display_Value (STErrRead, R_Error_Count);
NAK_Sent = TRUE;
Send_NAK();
}
State = R_Get_DLE;
break;
case R_Send_ACK :
if ( !Aborting )
Send_ACK();
State = R_Get_DLE; /* wait for the next block */
break;
case R_Success :
ST_Display_Value (STComRead, R_Com_Data);
ST_Display_Value (STComSent, S_Com_Data);
if ( !Aborting )
seq_num = block_num;
R_Size = i;
R_Packet_Count++;
ST_Display_Value (STPacRead, R_Packet_Count);
return(TRUE);
break;
}
}
} /* Read_Packet */
static void Send_Data (BuffeR_Number)
int BuffeR_Number;
{
int i;
buf_type *p;
p = &SA_Buf[BuffeR_Number];
if (B_Plus && Use_CRC)
checksum = Init_CRC (0xffff);
else
checksum = 0;
buf_send_byte (dle);
buf_send_byte ('B');
buf_send_byte (p->seq + '0');
do_checksum (p->seq + '0');
for (i = 0; i <= p->num; i++ ) {
send_masked_byte (p->buf [i]);
do_checksum (p->buf[i]);
}
buf_send_byte (etx);
do_checksum (etx);
if (B_Plus && Use_CRC)
send_masked_byte (checksum >> 8);
send_masked_byte (checksum);
Bufferd_Flush();
}
static int Incr_SA (Old_Value)
int Old_Value;
{
if (Old_Value == Max_SA)
return(0);
else
return(Old_Value + 1);
}
#define Get_First_DLE 1
#define Get_First_Digit 2
#define Get_Second_DLE 3
#define Get_Second_Digit 4
static int ReSync()
{
int State,Digit_1;
send_byte (enq); /* Send <ENQ><ENQ> */
send_byte (enq);
State = Get_First_DLE;
while(1) {
switch (State) {
case Get_First_DLE :
if ( !read_byte() )
return(-1);
if ( ch == dle )
State = Get_First_Digit;
break;
case Get_First_Digit :
if ( !read_byte() )
return(-1);
if ( (ch >= '0') && (ch <= '9') ) {
Digit_1 = ch;
State = Get_Second_DLE;
} else if (ch == 'B')
return( ch );
break;
case Get_Second_DLE :
if ( !read_byte() )
return(-1);
if ( ch == dle )
State = Get_Second_Digit;
break;
case Get_Second_Digit :
if ( !read_byte() )
return(-1);
if ( (ch >= '0') && (ch <= '9') ) {
if (Digit_1 == ch )
return(ch);
else if (ch == 'B')
return( ch );
else {
Digit_1 = ch;
State = Get_Second_DLE;
}
} else
State = Get_Second_DLE;
break;
} /* case */
} /* while TRUE */
}
static int Get_ACK()
{
int State,
errors,
block_num,
i;
int Sent_ENQ;
int SA_Index;
Packet_Received = FALSE;
errors = 0;
Sent_ENQ = FALSE;
State = S_Get_DLE;
while ( 1 ) {
switch (State) {
case S_Get_DLE :
if ( ST_Check_Abort() && !Aborting ) {
ST_Display_String (STMsg,
"Aborting the upload per your request");
Send_Failure ("AAborted by user");
return(FALSE);
}
if ( !read_byte() )
State = S_Timed_Out;
else {
if ( ch == dle )
State = S_Get_Num;
else if (ch == nak )
State = S_Send_ENQ;
else if (ch == etx )
State = S_Send_NAK;
}
break;
case S_Get_Num :
if (!read_byte() )
State = S_Timed_Out;
else if ( (ch >= '0') && (ch <= '9') )
State = S_Have_ACK; /* Received ACK */
else if ( ch == 'B' ) {
if (!Aborting)
State = S_Get_Packet; /* Try to receive a Packet */
else
State = S_Skip_Packet; /* Try to skip a Packet */
} else if (ch == nak)
State = S_Send_ENQ;
else if (ch == ';') {
ST_Display_Value (STComRead, R_Com_Data);
State = S_Get_DLE;
} else
State = S_Timed_Out;
break;
case S_Get_Packet :
if (Read_Packet (TRUE, TRUE) ) {
Packet_Received = TRUE;
if (R_buffer [0] == 'F') {
Send_ACK();
return(FALSE);
}
State = S_Get_DLE; /* Stay here to find the ACK */
} else
State = S_Get_DLE;
break;
case S_Skip_Packet : /* Skip an incoming Packet */
if (!read_byte())
State = S_Timed_Out;
else if (ch == etx ) {
if (!read_masked_byte())
State = S_Timed_Out;
else if (!Use_CRC)
State = S_Get_DLE;
else if (!read_masked_byte())
State = S_Timed_Out;
else
State = S_Get_DLE;
}
break;
case S_Have_ACK :
block_num = ch - '0';
ST_Display_Value (STComSent, S_Com_Data);
ST_Display_Value (STComRead, R_Com_Data);
if ( SA_Buf[SA_Next_to_ACK].seq == block_num ) {
SA_Next_to_ACK = Incr_SA (SA_Next_to_ACK);
SA_Waiting = SA_Waiting - 1;
if (SA_Error_Count > 0 )
SA_Error_Count--;
return(TRUE);
} else if ( (SA_Buf[Incr_SA(SA_Next_to_ACK)].seq == block_num) &&
SA_Waiting == 2) {
SA_Next_to_ACK = Incr_SA (SA_Next_to_ACK);
SA_Next_to_ACK = Incr_SA (SA_Next_to_ACK);
SA_Waiting = SA_Waiting - 2;
if (SA_Error_Count > 0)
SA_Error_Count--;
return(TRUE);
} else if ( SA_Buf[SA_Next_to_ACK].seq == Incr_Seq(block_num) ) {
if ( Sent_ENQ )
State = S_Send_Data; /* Remote missed first block */
else
State = S_Get_DLE; /* Duplicate ACK */
} else {
if ( !Aborting ) /* While aborting, ignore any */
State = S_Timed_Out; /* ACKs that have been sent */
else
State = S_Get_DLE; /* which are not for the failure */
} /* Packet. */
Sent_ENQ = FALSE;
break;
case S_Timed_Out :
State = S_Send_ENQ;
break;
case S_Send_NAK :
errors++;
S_Error_Count++;
ST_Display_Value (STErrSent, S_Error_Count);
if (errors > max_Errors)
return(FALSE);
Send_NAK();
State = S_Get_DLE;
break;
case S_Send_ENQ :
errors++;
S_Error_Count++;
ST_Display_Value (STErrSent, S_Error_Count);
if ( (errors > max_Errors) || (Aborting && (errors > 3)) )
return(FALSE);
ch = ReSync();
if ( ch == (-1) )
State = S_Get_DLE;
else if (ch == 'B') {
if( !Aborting )
State = S_Get_Packet; /* Try to receive a Packet */
else
State = S_Skip_Packet; /* Try to skip a Packet */
} else
State = S_Have_ACK;
Sent_ENQ = TRUE;
break;
case S_Send_Data :
SA_Error_Count += 3;
if (SA_Error_Count >= 12) /* Stop Upload Send Ahead if too many */
SA_Max = 1; /* errors have occured */
SA_Index = SA_Next_to_ACK;
for ( i = 1 ; i <= SA_Waiting ; i++ ) {
Send_Data (SA_Index);
SA_Index = Incr_SA (SA_Index);
}
State = S_Get_DLE;
Sent_ENQ = FALSE;
break;
}
}
} /* Get_ACK */
static int send_Packet (size)
int size;
{
while ( SA_Waiting >= SA_Max ) {
if ( !Get_ACK() )
return(FALSE);
}
seq_num = Incr_Seq (seq_num);
SA_Buf [SA_Next_to_Fill].seq = seq_num;
SA_Buf [SA_Next_to_Fill].num = size;
Send_Data (SA_Next_to_Fill);
SA_Next_to_Fill = Incr_SA (SA_Next_to_Fill);
SA_Waiting = SA_Waiting + 1;
S_Packet_Count++;
ST_Display_Value (STComSent, S_Com_Data);
ST_Display_Value (STPacSent, S_Packet_Count);
return(TRUE);
}
static int SA_Flush()
{
while ( SA_Waiting > 0 ) {
if ( !Get_ACK() )
return(FALSE);
}
return( TRUE );
}
static void Send_Failure (Reason)
char Reason[];
{
int i;
buf_type *p;
SA_Next_to_ACK = 0;
SA_Next_to_Fill = 0;
SA_Waiting = 0;
Aborting = TRUE; /* Inform Get_ACK we're aborting ]*/
p = &SA_Buf [0];
p->buf [0] = 'F';
for ( i = 1 ; i <= strlen(Reason) ; i++ )
p->buf [i] = (Reason [i]);
if ( send_Packet (strlen(Reason)) )
SA_Flush(); /* Gotta wait for the Initiator to ACK it */
}
static int Send_File (name)
char name[];
{
int n;
FILE *data_File;
buf_type *p;
time_t now;
data_File = fopen (name,READ_OP);
if ( data_File == 0 ) {
ST_Display_String (STMsg, "Cannot find that file");
Send_Failure ("MFile not found");
return(FALSE);
}
fseek(data_File,0L,2); /* seek to end of file */
S_Remaining = ftell(data_File); /* how long is this file ? */
fseek(data_File,0L,0); /* back to the start, ready to go */
ST_Display_Value (STUplRem, S_Remaining);
S_Com_Data = 0;
R_Com_Data = 0;
time(&e_timer);
do {
p = &SA_Buf [SA_Next_to_Fill];
p->buf [0] = 'N';
n = fread (&p->buf[1], 1, Buffer_Size, data_File);
if ( n > 0 ) {
if (send_Packet (n) == FALSE) {
fclose(data_File);
return(FALSE);
}
S_File_Data = S_File_Data + (n);
S_File_Size = S_File_Size + (n);
S_Remaining = S_Remaining - (n);
ST_Display_Value (STUplSize, S_File_Size);
ST_Display_Value (STDataSent, S_File_Data);
ST_Display_Value (STUplRem, S_Remaining);
time(&now);
Time_Estimate = now - e_timer;
ST_Display_Value (STElapsed, Time_Estimate);
if ( Time_Estimate != 0 ) {
Com_Rate = S_Com_Data / Time_Estimate;
Data_Rate = S_File_Data / Time_Estimate;
ST_Display_Value (STComRate, Com_Rate);
ST_Display_Value (STDataRate, Data_Rate);
if ( Data_Rate != 0 ) {
Time_Estimate = S_Remaining / Data_Rate;
ST_Display_Value (STRemTime, Time_Estimate);
}
}
}
} while(n > 0);
if ( ferror(data_File) != 0) {
Send_Failure ("EFile read failure");
ST_Display_String (STMsg, "Read failure...aborting");
fclose(data_File);
return(FALSE);
}
p = &SA_Buf [SA_Next_to_Fill];
p->buf [0] = 'T';
p->buf [1] = 'C';
if ( send_Packet (2) == FALSE ) {
fclose (data_File);
return(FALSE);
} else {
fclose (data_File);
if (!SA_Flush())
return(FALSE);
return(TRUE);
}
} /* Send_File */
static void Do_Transport_Parameters()
{
int Quote_Set_Present;
int i;
buf_type *p;
if (BP_Special_Quoting) {
for ( i = 0 ; i < 8 ; i++ )
Our_QS[i] = BP_Special_Quote_Set[i];
} else {
for ( i = 0 ; i < 8 ; i++ )
Our_QS[i] = DQ_Minimal[i];
}
for ( i = R_Size + 1; i<=512; i++ )
R_buffer [i] = 0;
His_WS = R_buffer [1]; /* Pick out Initiator's parameters */
His_WR = R_buffer [2];
His_BS = R_buffer [3];
His_CM = R_buffer [4];
His_QS [0] = R_buffer [7];
His_QS [1] = R_buffer [8];
His_QS [2] = R_buffer [9];
His_QS [3] = R_buffer [10];
His_QS [4] = R_buffer [11];
His_QS [5] = R_buffer [12];
His_QS [6] = R_buffer [13];
His_QS [7] = R_buffer [14];
His_DR = R_buffer [15];
His_UR = R_buffer [16];
His_FI = R_buffer [17];
Quote_Set_Present = (R_Size >= 14 ? TRUE:FALSE);
p = &(SA_Buf[SA_Next_to_Fill]);
p->buf [0] = '+'; /* Prepare to return Our own parameters */
p->buf [1] = Def_WS;
p->buf [2] = Def_WR;
p->buf [3] = Def_BS;
p->buf [4] = Def_CM;
p->buf [5] = Def_DQ;
p->buf [6] = 0; /* No transport layer here */
for ( i = 0 ; i <= 7 ; i++ )
p->buf[i + 7] = Our_QS[i];
if ( BP_Auto_Resume ) /* Set Download Resume according to */
Def_DR = 2; /* user's preference */
else
Def_DR = 1;
p->buf [15] = Def_DR;
p->buf [16] = Def_UR;
p->buf [17] = Def_FI;
Update_Quote_Table (DQ_Full); /* Send the + Packet w/ full quoting */
if ( !send_Packet(17) )
return;
if ( SA_Flush() ) { /* Wait for host's ACK on Our Packet */
Our_WR = His_WS < Def_WR ? His_WS:Def_WR;
Our_WS = His_WR < Def_WS ? His_WR:Def_WS;
Our_BS = His_BS < Def_BS ? His_BS:Def_BS;
Our_CM = His_CM < Def_CM ? His_CM:Def_CM;
Our_DR = His_DR < Def_DR ? His_DR:Def_DR;
Our_UR = His_UR < Def_UR ? His_UR:Def_UR;
Our_FI = His_FI < Def_FI ? His_FI:Def_FI;
if (Our_BS == 0)
Our_BS = 4; /* Default */
Buffer_Size = Our_BS * 128;
B_Plus = TRUE;
if (Our_CM == 1)
Use_CRC = TRUE;
if (Our_WS != 0)
SA_Max = Max_SA;
}
Clear_Quote_Table(); /* Restore Our Quoting Set */
Update_Quote_Table (Our_QS);
if ( Quote_Set_Present ) /* Insert Initiator's Quote Set */
Update_Quote_Table (His_QS);
}
static void Check_Keep (data_File, Name)
FILE *data_File;
char Name[];
{
char yn;
char str[256];
fclose (data_File);
if ( (!BP_Auto_Resume) || (!B_Plus) || (Our_DR == 0) ) {
strcpy( str, "Do you wish to retain the partial " );
strcat( str, Name );
strcat( str, "?" );
ST_Yes_or_No( str, &yn );
} else
yn = 'Y';
if ( yn == 'N' || yn == 'n' ) {
unlink ( Name );
ST_Display_String (STMsg, "File erased.");
} else {
ST_Display_String (STMsg, "File retained.");
}
}
static void Extract_String() /* Extract next string of characters */
{
int Digit_Seen;
Digit_Seen = FALSE;
e_j = 0;
while ( e_i <= e_n ) {
if ( (R_buffer [e_i] >= '0') && (R_buffer [e_i] <= '9') ) {
Digit_Seen = TRUE;
e_j++;
Val_Str [e_j] = R_buffer [e_i];
} else if ( Digit_Seen ) {
Val_Str [0] = e_j;
return;
}
e_i++;
}
}
static void Process_File_Information()
{
int i;
e_n = R_Size - 1;
e_i = 4; /* Skip data type and compression flag */
Extract_String();
/* Val (Val_Str, R_Remaining, e_j); */
R_Remaining = 0;
for ( i = 1 ; i <= e_j ; i++ )
R_Remaining = (R_Remaining * 10) + (Val_Str[i] - '0');
R_Remaining = R_Remaining - R_File_Size; /* Adjust for Dow Resume */
ST_Display_Value (STDowRem, R_Remaining);
S_Packet_Count = 0;
R_Packet_Count = 0;
}
static int Receive_File (Name)
char Name[];
{
FILE *Data_File;
int status;
long File_Length=0L; /* For download resumption */
char Work_String[256];
int Packet_Len;
int i, n;
char yn;
char Dow_Type;
buf_type *p;
time_t now;
Dow_Type = 'D'; /* Assume normal downloading */
Data_File = fopen( Name, UPDATE_OP ); /* open for r/w first */
if ( Data_File != NULL ) {
if ( (Our_DR > 1) && BP_Auto_Resume )
Dow_Type = 'R'; /* Remote supports `Tf', let's try */
else if ( Our_DR > 0 ) {
ST_Display_String (STMsg, "File already exists.");
ST_Yes_or_No ("Do you wish to resume downloading? ", &yn);
if ( yn == 'Y' || yn == 'y' )
Dow_Type = 'R';
else
ST_Display_String (STMsg, "File being overwritten.");
}
}
switch( Dow_Type ) {
case 'D':
if( Data_File )
fclose( Data_File ); /* close the read/write file */
Data_File = fopen( Name, WRITE_OP ); /* open for write */
if (Data_File == NULL) {
Send_Failure ("CCannot create file");
return(FALSE);
}
Send_ACK();
break;
case 'R' : /* Resume download */
ST_Display_String (STMsg, "Calculating CRC");
p = &SA_Buf [SA_Next_to_Fill];
if ( Dow_Type == 'R' ) {
checksum = Init_CRC (0xffff);
do {
n = fread (&p->buf [0], 1, Buffer_Size, Data_File);
for ( i = 0 ; i < n ; i++ )
checksum = Upd_CRC(p->buf[i]);
} while( n > 0 );
} else
checksum = 0;
p->buf [0] = 'T';
p->buf [1] = 'r';
Packet_Len = 2;
File_Length = ftell(Data_File);
ltoa (File_Length, Work_String);
strcat( Work_String, " " );
for ( i = 0 ; i < strlen(Work_String); i++ ) {
p->buf [Packet_Len] = Work_String [i];
Packet_Len++;
}
ltoa ((long)checksum, Work_String);
strcat( Work_String, " " );
for ( i = 0 ; i < strlen(Work_String) ; i++ ) {
p->buf [Packet_Len] = Work_String [i];
Packet_Len++;
}
if ( !send_Packet (Packet_Len - 1) ) {
fclose (Data_File);
return(FALSE);
}
if ( !SA_Flush() ) {
fclose (Data_File);
return(FALSE);
}
R_File_Size = File_Length;
ST_Display_Value (STDowSize, R_File_Size);
ST_Display_String (STMsg, "Host calculating CRC...");
Resume_Flag = TRUE;
break;
}
/*
Process each incoming Packet until 'TC' Packet received or failure
*/
R_Packet_Count = 0;
S_Packet_Count = 0;
if( BP_Use_File_Size )
R_Remaining = BP_File_Size;
else
R_Remaining = 0;
while ( TRUE ) {
if ( Read_Packet (FALSE, FALSE) ) {
switch (R_buffer[0]) {
case 'N' :
if ( Resume_Flag ) {
ST_Display_String( STMsg, "Resuming Download" );
Resume_Flag = FALSE;
}
status = fwrite( &R_buffer[1], 1, R_Size - 1, Data_File );
if ( (status != (R_Size - 1)) ) {
ST_Display_String (STMsg, "Write failure...aborting");
Send_Failure ("EWrite failure");
Check_Keep (Data_File, Name);
return(FALSE);
}
R_File_Data = R_File_Data + (R_Size - 1);
ST_Display_Value (STDataRead, R_File_Data);
R_File_Size = R_File_Size + (status);
ST_Display_Value (STDowSize, R_File_Size);
time(&now);
Time_Estimate = now - e_timer;
ST_Display_Value (STElapsed, Time_Estimate);
if ( Time_Estimate != 0 ) {
Com_Rate = R_Com_Data / Time_Estimate;
Data_Rate = R_File_Data / Time_Estimate;
ST_Display_Value (STComRate, Com_Rate);
ST_Display_Value (STDataRate, Data_Rate);
} else
Data_Rate = 0;
if ( R_Remaining != 0 ) {
R_Remaining = R_Remaining - (R_Size - 1);
ST_Display_Value (STDowRem, R_Remaining);
if ( Data_Rate != 0 ) {
Time_Estimate = R_Remaining / Data_Rate;
ST_Display_Value (STRemTime, Time_Estimate);
}
}
Send_ACK();
break;
case 'T' :
if (R_buffer[1] == 'C') {
ST_Display_String (STMsg, "*** Transfer Complete ***");
status = fclose (Data_File);
if ( status == EOF ) {
ST_Display_String (STMsg,
"Failure during close...aborting");
Send_Failure ("EError during close");
Check_Keep (Data_File, Name);
return(FALSE);
}
Send_ACK();
return(TRUE);
} else if ( R_buffer [1] == 'I' ) {
Send_ACK();
Process_File_Information();
} else if ( (R_buffer [1] == 'f') && BP_Auto_Resume ) {
fclose (Data_File); /* So...replace the file */
Data_File = fopen(Name, WRITE_OP);
if ( Data_File == NULL ) {
Send_Failure ("CCannot create file");
ST_Display_String (STMsg,
"CRC check failed; cannot create file");
return(FALSE);
}
if (Our_FI != 0 || BP_Use_File_Size)
R_Remaining = R_Remaining + R_File_Size;
R_File_Size = 0;
ST_Display_String (STMsg,
"CRC check failed; overwriting file");
Resume_Flag = FALSE;
time(&e_timer);
S_Com_Data = 0;
R_Com_Data = 0;
Send_ACK();
} else {
ST_Display_String (STMsg,
"Invalid termination Packet...aborting");
Send_Failure ("NInvalid T Packet");
Check_Keep (Data_File, Name);
return(FALSE);
}
break;
case 'F' :
Send_ACK();
ST_Display_String (STMsg,
"Failure Packet received...aborting");
Check_Keep (Data_File, Name);
return(FALSE);
break;
}
} else {
if (!Aborting)
ST_Display_String (STMsg, "Download failure");
Check_Keep (Data_File, Name);
return(FALSE);
}
}
} /* Receive_File */
/* =================================================================== */
int BP_DLE_Seen()
{
int i;
Port_Update_Rate = 256;
ST_Initialize(0);
if ( !read_byte() )
return 0;
if (ch != 'B')
return 0;
SA_Next_to_ACK = 0; /* Initialize Send-ahead variables */
SA_Next_to_Fill = 0;
SA_Waiting = 0;
Aborting = FALSE;
Packet_Received = FALSE;
switch (PortBps) {
case bps110:
case bps150:
case bps300:
Port_Update_Rate = 32;
break;
case bps600:
case bps1200:
Port_Update_Rate = 64;
break;
case bps1800 :
case bps2400:
Port_Update_Rate = 128;
break;
case bps4800:
case bps9600:
Port_Update_Rate = 256;
break;
}
R_Counter = 0;
S_Counter = 0;
R_File_Data = 0;
S_File_Data = 0;
R_Com_Data = 0;
S_Com_Data = 0;
S_Packet_Count = 0;
R_Packet_Count = 0;
S_File_Size = 0;
R_File_Size = 0;
S_Error_Count = 0;
R_Error_Count = 0;
Resume_Flag = FALSE;
if (Read_Packet (TRUE, FALSE)) {
switch (R_buffer[0]) {
case 'T': /* File Transfer Application */
ST_Initialize(0);
ST_Display_Value (STComRead, R_Com_Data);
S_Com_Data = 0;
R_Com_Data = 0;
time(&e_timer);
switch (R_buffer[1]) {
case 'D' :
ST_Display_String (STUpDow, "Downloading ");
break;
case 'U' :
ST_Display_String (STUpDow, "Uploading ");
break;
default:
ST_Display_String (STMsg, "Unimplemented Transfer Function");
Send_Failure ("NUnimplemented Transfer function");
ST_Terminate();
return 0;
}
switch (R_buffer[2]) {
case 'A':
ST_Display_String (STType, "ASCII");
break;
case 'B':
ST_Display_String (STType, "Binary");
break;
default:
ST_Display_String (STMsg, "Unimplemented File Type");
Send_Failure ("NUnimplemented file type");
ST_Terminate();
return 0;
}
i = 2;
memset(filename,0,sizeof(filename));
while ((R_buffer[i] != 0) && (i < R_Size - 1)) {
i = i + 1;
filename[i-3] = R_buffer[i];
}
ST_Display_String (STFile, filename);
S_Packet_Count = (0);
R_Packet_Count = (0);
if (R_buffer[1] == 'U')
Send_File (filename);
else
Receive_File (filename);
ST_Terminate();
return 1;
break;
case '+': /* Received Transport Parameters Packet */
Do_Transport_Parameters();
break;
default: /* Unknown Packet; tell the host we don't know */
Send_Failure ("NUnknown Packet Type");
break;
} /* of case */
} /* of if Read_Packet then*/
return 0;
} /* DLE_Seen */